﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using QX.Game.PathFinder;
using System.Windows.Threading;
using System.Windows.Media.Animation;

namespace WPFGame.Windows
{
    /// <summary>
    /// UserControl12.xaml 的交互逻辑
    /// </summary>
    public partial class UserControl12 : UserControl
    {
        private Rectangle rect;//构造障碍物矩形
        private IPathFinder PathFinder;
        private List<PathFinderNode> path;//找到的路径
        private DispatcherTimer timer;//人物动画（寻径）计时器
        private byte[,] Matrix = new byte[1024, 1024];
        private int count = 1;
        private System.Drawing.Point Start = System.Drawing.Point.Empty;//寻径起始点
        private System.Drawing.Point End = System.Drawing.Point.Empty;//寻径终结点
        private const int GridSize = 20;//单元格大小
        private const int cost = 100;//寻径时每移动一个单元格所花费的时间(毫秒)
        private Storyboard pathStoryboard;//寻径动画
        /// <summary>
        /// 记录上次寻径时标记在地图上的椭圆点,方便在下次寻径时清除
        /// </summary>
        private List<Ellipse> OldPathEllipse = new List<Ellipse>();

        public UserControl12()
        {
            InitializeComponent();
            InitMap();
            InitMask();
            InitPlayer();
            InitMatrix();

            timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(100) };
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();

            //界面刷新
            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
        }

        //设置地图副本
        BitmapSource Deeper = new BitmapImage(new Uri(Environment.CurrentDirectory + @"\Maps\Deeper.jpg", UriKind.RelativeOrAbsolute));
        int X, Y;//主角当前的窗口真实坐标(非缩放)--脚底!
        Point target;//主角移动的最终目的
        void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            X = Convert.ToInt32(Canvas.GetLeft(Spirit) + SpiritCenterX * GridSize);
            Y = Convert.ToInt32(Canvas.GetTop(Spirit) + SpiritCenterY * GridSize);
            tbMsg.Text = PickColor(Deeper, X, Y).ToString();

            if (PickColor(Deeper, X, Y) == Colors.Black)//假如碰到障碍物则采用A*寻路
                AStarMove(target);
            else if (PickColor(Deeper, X, Y) == Colors.Yellow) //假如是传送点则条到坐标(200,20)
            {
                pathStoryboard.Stop();
                Canvas.SetLeft(Spirit, 200 - SpiritCenterX * GridSize);
                Canvas.SetTop(Spirit, 20 - SpiritCenterY * GridSize);
            }

            //用点记录移动轨迹
            Ellipse ell = new Ellipse();
            GradientStopCollection gsc = new GradientStopCollection();
            gsc.Add(new GradientStop(Colors.Snow, 0));
            gsc.Add(new GradientStop(Colors.OrangeRed, 1));
            ell.Fill = new RadialGradientBrush()
            {
                Center = new Point(0.5, 0.5),
                GradientOrigin = new Point(0.5, 0.5),
                GradientStops = gsc
            };

            ell.Width = 10;
            ell.Height = 10;
            c.Children.Add(ell);
            Canvas.SetLeft(ell,X);
            Canvas.SetTop(ell, Y);
            Canvas.SetZIndex(ell, -1);
            OldPathEllipse.Add(ell);
        }

        /// <summary>
        /// 图片上某点取色
        /// </summary>
        /// <param name="bitmapsource">被取色的图片源</param>
        /// <param name="x">该点X坐标</param>
        /// <param name="y">该点Y坐标</param>
        /// <returns></returns>
        private Color PickColor(BitmapSource bitmapsource, int x, int y)
        {
            CroppedBitmap crop = new CroppedBitmap(bitmapsource, new Int32Rect(x, y, 1, 1));
            byte[] pixels = new byte[4];
            try
            {
                crop.CopyPixels(pixels, 4, 0);
                crop = null;
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.ToString());
            }
            //蓝pixels[0] 绿pixels[1]  红pixels[2] 透明度pixels[3]
            return Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
        }

        void timer_Tick(object sender, EventArgs e)
        {
            //如果路径不存在则停止寻径
            if ((pathStoryboard != null && path != null && pathStoryboard.GetCurrentTime() == TimeSpan.FromMilliseconds(100 * path.Count)))
            {
                timer.Stop();
                Spirit.Source = new BitmapImage(new Uri(Environment.CurrentDirectory + @"\Players\J\130\stand\1.png"));
                return;
            }
            Spirit.Source = cutImage(Environment.CurrentDirectory + @"\Players\J\130\run\left.png", count * 150, 0, 150, 150);
            count = count == 11 ? 0 : count + 1;
        }

        private BitmapSource cutImage(string iamgeUri, int x, int y, int w, int h)
        {
            return new CroppedBitmap(
                BitmapFrame.Create(new Uri(iamgeUri)),
                new Int32Rect(x, y, w, h));
        }

        /// <summary>
        /// 初始化地图二维矩阵，以单元格值为0或1来判断是否有障碍物。
        /// </summary>
        private void InitMatrix()
        {
            for (int x = 0; x < Matrix.GetUpperBound(0); x++)
            {
                for (int y = 0; y < Matrix.GetUpperBound(1); y++)
                    Matrix[x, y] = 1;//默认为1表示可通过
            }

            //构建障碍物
            for (int y = 22; y <= 24; y++)
            {
                for (int x = 5; x <= 16; x++)
                {
                    //障碍物在矩阵中用0表示
                    Matrix[x, y] = 0;
                    rect = new Rectangle();
                    rect.Fill = new SolidColorBrush(Colors.GreenYellow);
                    rect.Opacity = 0.3;
                    rect.Stroke = new SolidColorBrush(Colors.Gray);
                    rect.Width = GridSize;
                    rect.Height = GridSize;
                    c.Children.Add(rect);
                    Canvas.SetLeft(rect, x * GridSize);
                    Canvas.SetTop(rect, y * GridSize);
                }
            }
            for (int y = 11; y <= 14; y++)
            {
                for (int x = 27; x <= 31; x++)
                {
                    //障碍物在矩阵中用0表示
                    Matrix[x, y] = 0;
                    rect = new Rectangle();
                    rect.Fill = new SolidColorBrush(Colors.GreenYellow);
                    rect.Opacity = 0.3;
                    rect.Stroke = new SolidColorBrush(Colors.Gray);
                    rect.Width = GridSize;
                    rect.Height = GridSize;
                    c.Children.Add(rect);
                    Canvas.SetLeft(rect, x * GridSize);
                    Canvas.SetTop(rect, y * GridSize);
                }
            }
            for (int y = 18; y <= 21; y++)
            {
                for (int x = 33; x <= 37; x++)
                {
                    //障碍物在矩阵中用0表示
                    Matrix[x, y] = 0;
                    rect = new Rectangle();
                    rect.Fill = new SolidColorBrush(Colors.GreenYellow);
                    rect.Opacity = 0.3;
                    rect.Stroke = new SolidColorBrush(Colors.Gray);
                    rect.Width = GridSize;
                    rect.Height = GridSize;
                    c.Children.Add(rect);
                    Canvas.SetLeft(rect, x * GridSize);
                    Canvas.SetTop(rect, y * GridSize);
                }
            }


        }

        Image Spirit;
        /// <summary>
        /// 初始化角色
        /// </summary>
        private void InitPlayer()
        {
            Spirit = new Image() { Width = 150, Height = 150 };
            c.Children.Add(Spirit);
            Canvas.SetLeft(Spirit, 20);
            Canvas.SetTop(Spirit, 20);
        }

        int SpiritCenterX = 4; //主角脚底离主角图片左边的距离(游戏坐标系中)
        int SpiritCenterY = 5; //主角脚底离主角顶部的距离(游戏坐标系中)
        //游戏坐标系中Spirit坐标(缩小操作)
        public int SpiritGameX
        {
            get { return ((int)Canvas.GetLeft(Spirit) / GridSize) + SpiritCenterX; }
        }

        public int SpiritGameY
        {
            get { return ((int)Canvas.GetTop(Spirit) / GridSize) + SpiritCenterY; }
        }

        //窗口坐标系中Spirit坐标(放大操作)
        public int SpiritWindowX
        {
            get { return (SpiritGameX - SpiritCenterX) * GridSize; }
        }

        public int SpiritWindowY
        {
            get { return (SpiritGameY - SpiritCenterY) * GridSize; }
        }


        Image Mask1, Mask2;
        /// <summary>
        /// 初始化地图遮罩层
        /// </summary>
        private void InitMask()
        {
            Mask1 = new Image() { Width = 238, Height = 244, Opacity = 0.7, Source = new BitmapImage(new Uri(Environment.CurrentDirectory + @"\Maps\Mask1.png", UriKind.RelativeOrAbsolute)) };
            Mask2 = new Image() { Width = 198, Height = 221, Opacity = 0.7, Source = new BitmapImage(new Uri(Environment.CurrentDirectory + @"\Maps\Mask2.png", UriKind.RelativeOrAbsolute)) };
            c.Children.Add(Mask1); c.Children.Add(Mask2);
            Canvas.SetLeft(Mask1, 185); Canvas.SetLeft(Mask2, 446);
            Canvas.SetTop(Mask1, 220); Canvas.SetTop(Mask2, 11);
            Canvas.SetZIndex(Mask1, 10000); Canvas.SetZIndex(Mask2, 10000);
        }



        Image Map;
        /// <summary>
        /// 初始化地图
        /// </summary>
        private void InitMap()
        {
            Map = new Image()
            {
                Width = 800,
                Height = 600,
                Source = new BitmapImage(new Uri(Environment.CurrentDirectory + @"\Maps\Map2.jpg", UriKind.RelativeOrAbsolute))
            };
            c.Children.Add(Map);
            Canvas.SetZIndex(Map, -1);
        }




        private void c_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            timer.Start();//点击开始跑动

            //假如点到的地方不是障碍物
            Point p = e.GetPosition(c);
            if (PickColor(Deeper, (int)p.X, (int)p.Y) != Colors.Black)
            {
                target = p;
                NormalMove(p); //直线移动
                //AStarMove(p); //纯A*寻路算法
            }
        }

        /// <summary>
        /// 普通移动
        /// </summary>
        /// <param name="p">目标点</param>
        private void NormalMove(Point p)
        {
            //重新定位
            p = new Point(p.X - SpiritCenterX * GridSize, p.Y - SpiritCenterY * GridSize);
            pathStoryboard = new Storyboard();//创建移动动画
            //创建X轴方向动画
            DoubleAnimation daX = new DoubleAnimation()
            {
                From = Canvas.GetLeft(Spirit),
                To = p.X,
                Duration = TimeSpan.FromMilliseconds(1000),
            };
            Storyboard.SetTarget(daX, Spirit);
            Storyboard.SetTargetProperty(daX, new PropertyPath("(Canvas.Left)"));
            pathStoryboard.Children.Add(daX);
            //创建Y轴方向动画
            DoubleAnimation daY = new DoubleAnimation()
            {
                From = Canvas.GetTop(Spirit),
                To = p.Y,
                Duration = TimeSpan.FromMilliseconds(1000),
            };
            Storyboard.SetTarget(daY, Spirit);
            Storyboard.SetTargetProperty(daY, new PropertyPath("(Canvas.Top)"));
            pathStoryboard.Children.Add(daY);
            pathStoryboard.Begin();
        }

        /// <summary>
        /// A*移动
        /// </summary>
        /// <param name="p">目标点</param>
        private void AStarMove(Point p)
        {
            Start = new System.Drawing.Point(SpiritGameX, SpiritGameY);//设置寻径起点坐标
            End = new System.Drawing.Point((int)p.X / GridSize, (int)p.Y / GridSize);//设置寻径终点坐标

            PathFinder = new PathFinderFast(Matrix);
            PathFinder.Formula = HeuristicFormula.Manhattan;//使用曼哈顿A*算法
            path = PathFinder.FindPath(Start, End);//开始寻径

            if (path == null)
            {
                //MessageBox.Show("无可用路径!");
                return;
            }
            else
            {
                /*
                 * 因为根据A*原理算出的path是反向序列的，即由终点开始到起点的点集，
                 * 但是我们需要得到的是正向的点集，这样在后面可以更方便调用。
                 * 所以这里就用到了反向换算来计算出正向点集Point[] framePosition。
                 */
                Point[] framePosition = new Point[path.Count];//定义关键帧坐标集
                for (int i = path.Count - 1; i >= 0; i--)
                    //从起点开始以GridSize为单位，顺序填充关键帧坐标集，并进行坐标系放大
                    framePosition[path.Count - 1 - i] = new Point(path[i].X * GridSize, path[i].Y * GridSize);

                //创建寻径动画
                pathStoryboard = new Storyboard();
                //创建X轴方向逐帧动画
                DoubleAnimationUsingKeyFrames daKeyFramesX = new DoubleAnimationUsingKeyFrames()
                {
                    Duration = TimeSpan.FromMilliseconds(cost * path.Count)//总共花费时间 = path.Count * cost
                };
                Storyboard.SetTarget(daKeyFramesX, Spirit);
                Storyboard.SetTargetProperty(daKeyFramesX, new PropertyPath("(Canvas.Left)"));

                //创建Y轴方向逐帧动画
                DoubleAnimationUsingKeyFrames daKeyFramesY = new DoubleAnimationUsingKeyFrames()
                {
                    Duration = TimeSpan.FromMilliseconds(cost * path.Count)
                };
                Storyboard.SetTarget(daKeyFramesY, Spirit);
                Storyboard.SetTargetProperty(daKeyFramesY, new PropertyPath("(Canvas.Top)"));

                for (int i = 0; i < framePosition.Count(); i++)
                {
                    //加入X轴方向的匀速关键帧
                    LinearDoubleKeyFrame keyFrame = new LinearDoubleKeyFrame()
                    {
                        Value = i == 0 ? Canvas.GetLeft(Spirit) : framePosition[i].X - SpiritCenterX * GridSize,
                        KeyTime = TimeSpan.FromMilliseconds(i * cost),
                    };
                    daKeyFramesX.KeyFrames.Add(keyFrame);
                    //加入Y轴方向的匀速关键帧
                    keyFrame = new LinearDoubleKeyFrame()
                    {
                        Value = i == 0 ? Canvas.GetTop(Spirit) : framePosition[i].Y - SpiritCenterY * GridSize,
                        KeyTime = TimeSpan.FromMilliseconds(i * cost)
                    };
                    daKeyFramesY.KeyFrames.Add(keyFrame);
                }
                pathStoryboard.Children.Add(daKeyFramesX);
                pathStoryboard.Children.Add(daKeyFramesY);

                //故事板动画开始
                pathStoryboard.Begin();

                //if (OldPathEllipse != null)
                //{
                //    foreach (Ellipse el in OldPathEllipse.ToArray())
                //    {
                //        c.Children.Remove(el);
                //    }
                //    OldPathEllipse.Clear();
                //}

                ////用点记录移动轨迹
                //for (int i = path.Count - 1; i >= 0; i--)
                //{
                //    Ellipse ell = new Ellipse();
                //    GradientStopCollection gsc = new GradientStopCollection();
                //    gsc.Add(new GradientStop(Colors.Snow, 0));
                //    gsc.Add(new GradientStop(Colors.OrangeRed, 1));
                //    ell.Fill = new RadialGradientBrush()
                //    {
                //        Center = new Point(0.5, 0.5),
                //        GradientOrigin = new Point(0.5, 0.5),
                //        GradientStops = gsc
                //    };

                //    ell.Width = 10;
                //    ell.Height = 10;
                //    c.Children.Add(ell);
                //    Canvas.SetLeft(ell, path[i].X * GridSize);
                //    Canvas.SetTop(ell, path[i].Y * GridSize);
                //    Canvas.SetZIndex(ell, -1);
                //    OldPathEllipse.Add(ell);
                //}
            }
        }
    }
}
